package com.rainman.simpleredis.bootstart.configuration;

import com.rainman.simpleredis.core.SimpleRedis;
import com.rainman.simpleredis.core.config.SimpleDelayWorkDataInterface;
import com.rainman.simpleredis.core.config.SimpleRedisConfig;
import com.rainman.simpleredis.core.config.RedisInterface;

import com.rainman.simpleredis.core.delay_work.SimpleDelayWorkerInterface;
import com.rainman.simpleredis.core.process_flow.ProcessWorkerReturn;
import com.rainman.simpleredis.core.process_flow.SimpleProcessFlowWorkerInterface;
import com.rainman.simpleredis.core.scheduled.ScheduledInfo;
import com.rainman.simpleredis.core.scheduled.SimpleScheduledWorkerInterface;
import com.rainman.simpleredis.core.simplemq.SimpleMqWorkerInterface;
import com.rainman.simpleredis.core.simplemq.WorkerReturn;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;

import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Configuration
@EnableConfigurationProperties(SimpleRedisProperties.class)
public class SimpleRedisAutoConfiguration {

    @Autowired
    SimpleRedisProperties simpleRedisProperties;

    private final StringRedisTemplate stringRedisTemplate;

    RedisConnectionFactory redisConnectionFactory;


    @Lazy
    @Autowired
    List<SimpleMqWorkerInterface> simpleMqWorkerInterfaces;


    @Lazy
    @Autowired
    List<SimpleScheduledWorkerInterface> scheduledWorkerInterfaces;


    @Lazy
    @Autowired
    List<SimpleProcessFlowWorkerInterface> processFlowWorkerInterfaces;



    @Autowired
    SimpleDelayWorkDataInterface simpleDelayWorkDataInterface;

    @Autowired
    SimpleDelayWorkerInterface simpleDelayWorkerInterface;

    private SimpleRedisConfig simpleRedisConfig;
    

    SimpleRedisAutoConfiguration(RedisConnectionFactory redisConnectionFactory){

        this.redisConnectionFactory=redisConnectionFactory;

        stringRedisTemplate=new StringRedisTemplate();
        stringRedisTemplate.setConnectionFactory(redisConnectionFactory);
        stringRedisTemplate.afterPropertiesSet();

    }

    @Bean
    @ConditionalOnMissingBean(RedisMessageListenerContainer.class)
    RedisMessageListenerContainer container(SimpleRedis simpleRedis) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(redisConnectionFactory);
        container.addMessageListener(new RedisSubListener(simpleRedis),new ChannelTopic(
                simpleRedisConfig.getKeyHead()+ simpleRedisConfig.getProduct()));
        return container;
    }


    @Bean
    @ConditionalOnMissingBean(SimpleRedis.class)
    public SimpleRedis simpleRedis( ) {

        simpleRedisConfig =new SimpleRedisConfig();
        if(simpleRedisProperties.getCharset()!=null){

            simpleRedisConfig.setCharset(simpleRedisProperties.getCharset());
        }
        if(simpleRedisProperties.getProduct()!=null){
            simpleRedisConfig.setProduct(simpleRedisProperties.getProduct());

        }
        if(simpleRedisProperties.getMqVer()!=null){
            simpleRedisConfig.setVer(simpleRedisProperties.getMqVer());

        }

        simpleRedisConfig.setRedisInterface(new RedisInterface() {
            @Override
            public Set<String> keys(String pa) {
                return stringRedisTemplate.keys(pa);
            }

            @Override
            public Boolean hasKey(String key) {
                return stringRedisTemplate.hasKey(key);
            }

            @Override
            public Boolean delete(String key) {
                return stringRedisTemplate.delete(key);
            }

            @Override
            public void set(String key, String value) {
                stringRedisTemplate.opsForValue().set(key,value);
            }

            @Override
            public void set(String key, String value, Duration timeout) {

                stringRedisTemplate.opsForValue().set(key,value,timeout);
            }

            @Override
            public Boolean setIfAbsent(String key, String value, Duration timeout) {

                return stringRedisTemplate.opsForValue().setIfAbsent(key,value,timeout);
            }

            @Override
            public String getValue(String key) {
                return stringRedisTemplate.opsForValue().get(key);
            }

            @Override
            public Long rightPush(String key, String value) {
                return stringRedisTemplate.opsForList().rightPush(key, value);
            }

            @Override
            public String leftPop(String key, long timeout, TimeUnit unit) {

                return stringRedisTemplate.opsForList().leftPop(key, timeout, unit);
            }

            @Override
            public String index(String key, long index) {
                return stringRedisTemplate.opsForList().index(key,0);
            }

            @Override
            public Long curRedisTime() {

                Long curRedisTime = stringRedisTemplate.execute(RedisServerCommands::time);

                return curRedisTime;
            }

            @Override
            public Long increment(String key) {


                return stringRedisTemplate.opsForValue().increment(key);
            }

            @Override
            public void convertAndSend(String channel, String message) {
                stringRedisTemplate.convertAndSend(channel,message);
            }


        });
        //System.out.println(simpleMqWorkerInterfaces);

        simpleRedisConfig.setMqWorkerInterfaces(new ArrayList<>());
        simpleRedisConfig.setScheduledWorkerInterfacesMap(new HashMap<>());
        simpleRedisConfig.setFlowWorkerInterfaceHashMap(new HashMap<>());


        if(simpleDelayWorkDataInterface !=null){
            System.out.println("开启，延迟任务生产模块");
            simpleRedisConfig.setSimpleDelayWorkDataInterface(simpleDelayWorkDataInterface);
        }

        if(simpleDelayWorkerInterface !=null){
            System.out.println("开启，延迟任务消费模块");
            simpleRedisConfig.setSimpleDelayWorkerInterface(simpleDelayWorkerInterface);
        }

        return new SimpleRedis(simpleRedisConfig);
    }



    @Bean
    public SimpleRedisInitConfiguration simpleRedisInitConfiguration( SimpleRedis simpleRedis,
                                                                      List<SimpleMqWorkerInterface> simpleMqWorkerInterfaces,
                                                                      List<SimpleScheduledWorkerInterface> scheduledWorkerInterfaces,
                                                                      List<SimpleProcessFlowWorkerInterface> processFlowWorkerInterfaces) {
        return new SimpleRedisInitConfiguration(simpleRedis,simpleMqWorkerInterfaces,scheduledWorkerInterfaces,processFlowWorkerInterfaces);
    }


    @Bean
    public SimpleRedisCacheManager simpleRedisCacheManager( ) {
        return new SimpleRedisCacheManager(simpleRedisProperties,
                RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),
                RedisCacheConfiguration.defaultCacheConfig());
    }


    //--------------------------------------------------------
    @Bean
    public SimpleMqWorkerInterface simpleMqWorkerInterface( ) {
        return new SimpleMqWorkerInterface() {
            @Override
            public WorkerReturn doWork(String targetType, String targetId, String msgValue) {
                return null;
            }

            @Override
            public Boolean matchTargetType(String targetType) {
                return false;
            }
        };
    }

    @Bean
    public SimpleScheduledWorkerInterface simpleScheduledWorkerInterface( ) {
        return new SimpleScheduledWorkerInterface() {
            @Override
            public void doWork() {
            }

            @Override
            public String key() {
                return null;
            }

            @Override
            public ScheduledInfo info() {
                return null;
            }
        };
    }

    @Bean
    public SimpleProcessFlowWorkerInterface simpleProcessFlowWorkerInterface( ) {
        return new SimpleProcessFlowWorkerInterface() {
            @Override
            public ProcessWorkerReturn doWork(List<String> params) {
                return null;
            }

            @Override
            public ProcessWorkerReturn unDoWork(List<String> params, String returnInfo) {
                return null;
            }

            @Override
            public String workType() {
                return null;
            }
        };
    }


}
